#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <getopt.h>

#define MES_STR       "Hello world!"
#define FD_ARRAY(x)   (sizeof(x)/sizeof(x[0]))

void print_usage(char *progname)
{
	printf("%s usage: \n", progname);
//	printf("-i(--ipaddr): sepcify server IP address\n");
	printf("-p(--port): sepcify server port\n");
	printf("-h(--help): print this help information\n");

	return;
}

int main(int argc, char** argv)
{

	int        daemon_run = 0;
	int        i = 0;
	int        maxfd = -1;
	int        found;
	fd_set     rdset;
	int       fd_array[1024];
	int        sv = -1;

	int        sockfd = -1;
	int        on = 1;
	int        BACKLOG = 1024;
	int        acfd = -1;
	int        rv = -1;
	int        ch = -1;
	socklen_t  cliaddr_len;
//	int        PORT=12345;
//	char       *ID = "192.168.41.1";
	int        PORT=0;
//	char       *ID
	char       buf[1024];
	struct     sockaddr_in serv_addr;
	struct     sockaddr_in cli_addr;
	struct     option opts[] ={
//	      	   {"ipaddr", required_argument,NULL,'i'},
		   {"port", required_argument,NULL,'p'},
		   {"help", no_argument,NULL,'h'},
		   {NULL, 0, NULL, 0}
	};

	while((ch=getopt_long(argc, argv, "i:p:h", opts, NULL)) != -1 )
	{
		switch(ch)
		{
//			case'i':
//				ID=optarg;
				break;
		       	case'p':
                                PORT=atoi(optarg);
                                break;
		       	case'h':
                                print_usage(argv[0]);
                                return 0;
		}
	}
	
	if(/*!ID ||*/ !PORT)
	{
		print_usage(argv[0]);
		return 0;
	}


	sockfd=socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd<0)
	{
		printf("Create socket filetrue: %s\n",strerror(errno));
		return -1;
	}
        printf("Create socket successful: %d\n",sockfd);

	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));


	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	rv=bind(sockfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
	if(rv<0)
	{
                printf("Bind filetrue: %s\n",strerror(errno));
                return -2;
        }
        printf("socket[%d] bind on port[%d] for all IP ok\n",sockfd,PORT);

	listen(sockfd, BACKLOG);

	if(daemon_run)
	{
		daemon(0,0);
	}


	memset(&fd_array, 0, sizeof(fd_array));

	for(i=0; i<FD_ARRAY(fd_array) ; i++)
	{
		fd_array[i] = -1;

	}
	fd_array[0] = sockfd;

	printf("add sockfd to fd_array successful\n");


	for( ; ; )
	{
		FD_ZERO(&rdset);
	//	FD_ZERO(&wtset);

		for(i=0; i<FD_ARRAY(fd_array); i++)
		{
			if(fd_array[i]<0)
				continue;

			maxfd = fd_array[i] > maxfd ? fd_array[i] : maxfd;
			FD_SET(fd_array[i], &rdset);
//			FD_SET(fd_array[i], &wtset);
		}


		sv = select(maxfd+1, &rdset, NULL, NULL, NULL );
		if(sv<0)
		{
			printf("select failure:%s\n", strerror(errno));
			break;
		}
		else if(sv==0)
		{
			printf("select get timeout\n");
			continue;
		}

		else
		{
			if(FD_ISSET(sockfd, &rdset))
			{
				printf("Start waitting for accept new client...\n");
				cliaddr_len = sizeof(cli_addr);
				acfd=accept(sockfd, (struct sockaddr*)&cli_addr,&cliaddr_len);
					if(acfd<=0)
					{
						printf("Accept new cilent filetrue: %s or disconnect!\n",strerror(errno));
					       	close(acfd);
						break;
				       	}
					else
					{
					
						found = 0;
						for(i=0; i<FD_ARRAY(fd_array); i++)
						{
							if(fd_array[i]<0)
							{
								printf("accept new client[%d] and add it to fd_array\n",acfd);
			  					printf("accept new client[%d:%d] on port[%d]\n",cli_addr.sin_addr.s_addr, cli_addr.sin_port, PORT);
                                                                printf("acfd: %d\n",acfd);
								fd_array[i] = acfd;
								found = 1;
								break;
							}
						}
						if(!found)
						{
							printf("accept new client[%d] but full, so refuse it!\n", acfd);
							close(acfd);
							break;
						}

					}
			}
			else
			{
				for(i=0; i<FD_ARRAY(fd_array); i++)
				{

					if(fd_array[i]<0 || !FD_ISSET(fd_array[i], &rdset))
						continue;                                          //bianli
					memset(&buf, 0, sizeof(buf));
					rv=read(fd_array[i], buf, sizeof(buf));
					if(rv<0)
					{
	 					printf("Read from client [%d:%d] filetrue: %s\n",cli_addr.sin_addr.s_addr,cli_addr.sin_port,strerror(errno));
	 					close(fd_array[i]);
						fd_array[i] = -1;
						break;
	 				}
					else if(rv==0)
					{
						printf("Client connect to server get disconnect!\n");
						close(fd_array[i]);
						fd_array[i] = -1;
						break;;
					}
					printf("read from client data:%d\n",rv);
					printf("Read from client:%s\n",buf);
	
					rv=write(fd_array[i],MES_STR, strlen(MES_STR));
					printf("rv:%d\n",rv);
					if(rv<0)
					{
						printf("Write to client[%d:%d] filetrue: %s\n",cli_addr.sin_addr.s_addr,cli_addr.sin_port,strerror(errno));
						close(fd_array[i]);
						fd_array[i] = -1;
						break;
					}
					printf("write to client data:%d\n",rv);
					
				}
			}
		}
	}
CleanUp:
	close(fd_array[i]);
	return 0;
}










	
/*	while(1)
	{

		printf("Start waitting for accept new client...\n");
		cliaddr_len = sizeof(cli_addr);
		acfd=accept(sockfd, (struct sockaddr*)&cli_addr,&cliaddr_len);
		if(acfd<0)
		{
			printf("Accept new cilent filetrue: %s\n",strerror(errno));
                        return -3;
                }
	     
		printf("accept new client[%d:%d] on port[%d]\n",cli_addr.sin_addr.s_addr, cli_addr.sin_port, PORT);
		printf("acfd: %d\n",acfd);
               
	       
		memset(&buf, 0, sizeof(buf));
                rv=read(acfd, buf, sizeof(buf));
                if(rv<0)
                {
                        printf("Read from client [%d:%d] filetrue: %s\n",cli_addr.sin_addr.s_addr,cli_addr.sin_port,strerror(errno));
                        return -5;
                }
                else if(rv==0)
                {
                        printf("Client connect to server get disconnect!\n");
                        return -6;
                }
                printf("read from client data:%d\n",rv);
                printf("Read from client:%s\n",buf);
	
		rv=write(acfd,MES_STR, strlen(MES_STR));
		printf("rv:%d\n",rv);
		if(rv<0)
                {
		    	printf("Write to client[%d:%d] filetrue: %s\n",cli_addr.sin_addr.s_addr,cli_addr.sin_port,strerror(errno));
                        return -4;
                }
	       	printf("write to client data:%d\n",rv);

        	memset(&buf, 0, sizeof(buf));
        	rv=read(acfd, buf, sizeof(buf));
        	if(rv<0)
                {
                        printf("Read from client [%d:%d] filetrue: %s\n",cli_addr.sin_addr.s_addr,cli_addr.sin_port,strerror(errno));
                        return -5;
                }
		else if(rv==0)
                {
                        printf("Client connect to server get disconnect!\n");
         		return -6;
                }
		printf("read from client data:%d\n",rv);
		printf("Read from client:%s\n",buf);   
	}
	close(acfd);
 	close(sockfd);

	return 0;

}

*/








